package com.geovis.emergency.spd.biz.system.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geovis.common.core.constant.CommonConstants;
import com.geovis.common.core.exception.BizException;
import com.geovis.common.mybatis.page.PageParam;
import com.geovis.common.mybatis.page.PageResult;
import com.geovis.emergency.spd.biz.filing.service.IFilingSystemUserService;
import com.geovis.emergency.spd.biz.system.mapper.SystemMainRoleMapper;
import com.geovis.emergency.spd.biz.pc.mapper.PcDrillUserRoleMapper;
import com.geovis.emergency.spd.biz.system.mapper.SystemRoleMapper;
import com.geovis.emergency.spd.biz.system.mapper.SystemUserMapper;
import com.geovis.emergency.spd.biz.system.mapper.SystemUserRoleMapper;
import com.geovis.emergency.spd.biz.system.service.*;
import com.geovis.emergency.spd.entity.pc.pojo.enums.StatusEnum;
import com.geovis.emergency.spd.entity.system.entity.*;
import com.geovis.emergency.spd.entity.system.pojo.constant.SystemConstant;
import com.geovis.emergency.spd.entity.system.pojo.dto.*;
import com.geovis.emergency.spd.entity.system.pojo.enums.RoleTypeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author 王响
 * @since 2020-07-15
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements ISystemUserService {

    private final ISystemUserRoleService systemUserRoleService;

    private final ISystemResourcesService systemResourcesService;

    private final SystemRoleMapper systemRoleMapper;

    private final PasswordEncoder passwordEncoder;

    private final ISystemDeptUserService systemDeptUserService;

    private final PcDrillUserRoleMapper pcDrillRoleUserMapper;

    private final SystemMainRoleMapper systemMainRoleMapper;

    private final SystemUserRoleMapper systemUserRoleMapper;

    private final ISystemRoleResourcesService systemRoleResourcesService;
    @Autowired
    @Lazy
    private ISystemDeptService systemDeptService;

    @Value("${geovis.filing-url}")
    private String filingUrl;

    private final IFilingSystemUserService filingSystemUserService;

    @Override
    public LoginUserInfoDTO getByUserId(String userId) {
        LoginUserInfoDTO loginUserInfoDTO = baseMapper.selectByUserId(userId);
//
        //查询用户主角色
        SystemUserRole sur = systemUserRoleMapper.selectOne(
                Wrappers.lambdaQuery(SystemUserRole.class)
                        .eq(SystemUserRole::getUserId, userId)
        );
        if(sur==null)
        {
            throw new BizException("用户角色关系不存在");
        }
        SystemRole mr = systemRoleMapper.selectOne(
                Wrappers.lambdaQuery(SystemRole.class)
                        .eq(SystemRole::getId, sur.getRoleId())
                        .eq(SystemRole::getRoleType, RoleTypeEnum.SYSTEM)
        );
        if(mr==null)
        {
            throw new BizException("用户系统角色不存在");
        }
        //查询权限
        List<SystemRoleResources> srrs=systemRoleResourcesService.list(Wrappers.lambdaUpdate(SystemRoleResources.class).eq(SystemRoleResources::getRoleId,sur.getRoleId()));
        if(!CollectionUtils.isEmpty(srrs))
        {
            List<SystemResources> srs=systemResourcesService.listByIds(srrs.stream().map(SystemRoleResources::getResourcesId).collect(Collectors.toList()));
            loginUserInfoDTO.setPermissionList(srs.stream().map(SystemResources::getAuthName).collect(Collectors.toSet()));
        }
        loginUserInfoDTO.setRole(mr.getEnName());
        loginUserInfoDTO.setRoleName(mr.getName());
        return loginUserInfoDTO;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void removeByIdList(Set<String> idList) {
        if (CollUtil.isEmpty(idList)) {
            return;
        }

        // 1、删除角色-用户关联表
        systemUserRoleService.remove(Wrappers.lambdaUpdate(SystemUserRole.class).in(SystemUserRole::getUserId, idList));

        systemDeptUserService.remove(Wrappers.lambdaUpdate(SystemDeptUser.class).in(SystemDeptUser::getUserId, idList));

        // 2、删除用户
        removeByIds(idList);

    }



    @Override
    public boolean isContainAdmin(Set<String> idList) {
        List<SystemUser> users=this.list(Wrappers.lambdaUpdate(SystemUser.class).in(SystemUser::getId,idList).eq(SystemUser::getUserName,SystemConstant.ADMIN_USER_NAME));
        return !CollectionUtils.isEmpty(users);
    }

    @Override
    public PageResult<SystemUserDTO> listPage(PageParam<SystemUserQueryDTO> pageParam) {
        SystemUserQueryDTO queryDTO = pageParam.getQuery();
        IPage<SystemUserDTO> page = pageParam.buildPage();
        QueryWrapper<Object> wrapper = Wrappers.query();
        if (ObjectUtil.isNotEmpty(queryDTO)) {
            wrapper.like(ObjectUtil.isNotEmpty(queryDTO.getUserName()), "a.user_name", queryDTO.getUserName())
                    .like(ObjectUtil.isNotEmpty(queryDTO.getNickName()), "a.nick_name", queryDTO.getNickName())
                    .like(ObjectUtil.isNotEmpty(queryDTO.getRealName()), "a.real_name", queryDTO.getRealName())
                    .like(ObjectUtil.isNotEmpty(queryDTO.getPhone()), "a.phone", queryDTO.getPhone())
                    .eq(ObjectUtil.isNotEmpty(queryDTO.getDeptId()), "a.dept_id", queryDTO.getDeptId())
                    .eq("a.is_deleted", StatusEnum.FALSE.getCode());
        }
        baseMapper.selectByPage(page, wrapper);
        IPage<SystemUserDTO> userData= page.convert(data->{
            if(null!=data.getDeptId())
            {
                List<SystemDept> deptTree=buildDeptTree(data.getDeptId());
                data.setDeptList(deptTree);
                List<String> deptNames=deptTree.stream().map(SystemDept::getDeptName).collect(Collectors.toList());
                Collections.reverse(deptNames);
                data.setDeptName(String.join("/",deptNames));
            }

            return data;
        });
        return new PageResult<SystemUserDTO>(userData);
    }

    @Override
    public List<SystemUser> listByDeptIds(List<String> deptIds) {
       List<SystemDeptUser> deptUsers=systemDeptUserService.list(Wrappers.lambdaQuery(SystemDeptUser.class)
                .in(SystemDeptUser::getDeptId, deptIds));
       if(CollectionUtils.isEmpty(deptUsers))
       {
           return Collections.emptyList();
       }
       List<String> userIds=deptUsers.stream().map(SystemDeptUser::getUserId).collect(Collectors.toList());
       return baseMapper.selectBatchIds(userIds);
    }


    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void assignRole(SystemUserAssignRoleDTO assignRoleDTO) {

        if (ObjectUtil.isEmpty(assignRoleDTO) || ObjectUtil.isEmpty(assignRoleDTO.getId())) {
            return;
        }
        // 1、删除用户角色中间表
        systemUserRoleService.remove(Wrappers.lambdaUpdate(SystemUserRole.class).in(SystemUserRole::getUserId, assignRoleDTO.getId()));

        if (ObjectUtil.isEmpty(assignRoleDTO.getRoleIdList())) {
            return;
        }
        // 2、要保存用户角色中间表的列表
        List<SystemUserRole> systemUserRoleList = ListUtil.list(false);
        assignRoleDTO.getRoleIdList().forEach(roleId -> {
            SystemUserRole systemUserRole = new SystemUserRole()
                    .setUserId(assignRoleDTO.getId())
                    .setRoleId(roleId);
            systemUserRoleList.add(systemUserRole);
        });
        systemUserRoleService.saveBatch(systemUserRoleList);
    }
    private void assignSystemDeptUser(String userId,String userName,String deptId){
        //目前一个用户只会关联一个部门，所以关联记录只有一条
        SystemDeptUser deptUser = systemDeptUserService.getOne(
                Wrappers.lambdaQuery(SystemDeptUser.class)
                        .eq(SystemDeptUser::getUserId, userId)
        );
        if(deptUser==null)
        {
            SystemDeptUser sdu=new SystemDeptUser();
            sdu.setDeptId(deptId)
                    .setUserId(userId)
                    .setUserName(userName);
            systemDeptUserService.save(sdu);
            return;
        }
        deptUser.setDeptId(deptId)
                .setUserName(userName);
        systemDeptUserService.updateById(deptUser);
    }
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void save(SystemUserSaveDTO saveDTO) {

        // 1、检查用户名是否已存在
        Long saveUsernameCount = count(Wrappers.lambdaQuery(SystemUser.class).eq(SystemUser::getUserName, saveDTO.getUserName()));
        Assert.isTrue(saveUsernameCount < 1,"用户名【{}】已被使用！", saveDTO.getUserName());

        // 2、检查手机号是否已存在
        Long savePhoneCount = count(Wrappers.lambdaQuery(SystemUser.class).eq(SystemUser::getPhone, saveDTO.getPhone()));
        Assert.isTrue(savePhoneCount < 1,"手机号码【{}】已被使用！", saveDTO.getPhone());



        SystemUser systemUser = BeanUtil.toBean(saveDTO, SystemUser.class);
        //集成单点后，密码需要固定
        systemUser.setUserPassword(passwordEncoder.encode(SystemConstant.defaultPassword));
        systemUser.setDataStatus(CommonConstants.YES);

        // 4、保存用户信息
        save(systemUser);

        //保存用户角色
        SystemUserAssignRoleDTO assignRoleDTO = new SystemUserAssignRoleDTO();
        assignRoleDTO.setId(systemUser.getId())
                .setRoleIdList(CollUtil.list(false, saveDTO.getRoleIdList().get(0)));
        assignRole(assignRoleDTO);

        assignSystemDeptUser(systemUser.getId(), systemUser.getRealName(),systemUser.getDeptId());


    }

    private void saveOrUpdateFilingUser(String method,SystemUserSaveDTO saveDTO,SystemDept dept,SystemRole role)
    {
        String url=filingUrl+"/system/systemUser/"+method;
        Map<String, String> reqBody= new LinkedHashMap<>();
        reqBody.put("userName", saveDTO.getUserName());
        reqBody.put("userPassword", saveDTO.getUserPassword());
        reqBody.put("nickName", saveDTO.getNickName());
        reqBody.put("realName", saveDTO.getRealName());
        reqBody.put("phone", saveDTO.getPhone());
        reqBody.put("roleName", role.getName());
        reqBody.put("deptName", dept.getDeptName());
        RestTemplate restTemplate=new RestTemplate();
        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, String>> entity = new HttpEntity<Map<String, String>>(reqBody,header);
        ResponseEntity<String> response=restTemplate.exchange(url, HttpMethod.POST, entity,String.class);
        if(response.getStatusCode()!= HttpStatus.OK)
        {
            log.error("系统响应错误！");
            log.error("body:{}", response.getBody());
            throw new BizException("系统响应错误, 预案备案创建用户失败！");
        }
        Map<String,Object> resMap= JSONUtil.parseObj(response.getBody());
        Integer resCode=(Integer)resMap.get("code");
        if(resCode!=200)
        {
            throw new BizException("预案备案创建用户失败！");
        }
        return;
    }



    private List<SystemDept> buildDeptTree(String leafDeptId)
    {
        List<SystemDept> depts=systemDeptService.list(Wrappers.lambdaQuery(SystemDept.class));
        SystemDept leafDepd=depts.stream().filter(d->d.getId().equals(leafDeptId)).findFirst().get();
        List<SystemDept> deptTree=new ArrayList<>();
        deptTree.add(leafDepd);
        findDeptNames(leafDepd,depts,deptTree);
        return deptTree;
    }


    private void findDeptNames(SystemDept childDept,List<SystemDept> allDept,List<SystemDept> deptTree)
    {

        Optional<SystemDept> parentDept=allDept.stream().filter(d->childDept.getParentId()!=null && d.getId().equals(childDept.getParentId())).findFirst();
        if(parentDept.isPresent())
        {
            SystemDept dept=parentDept.get();
            deptTree.add(dept);
            findDeptNames(dept,allDept,deptTree);
        }
    }


    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void update(SystemUserUpdateDTO updateDTO) {
        // 1、检查用户名是否已存在
        Long updateUsernameCount = count(Wrappers.lambdaQuery(SystemUser.class)
                .eq(SystemUser::getUserName, updateDTO.getUserName())
                .ne(SystemUser::getId, updateDTO.getId()));
        Assert.isTrue(updateUsernameCount < 1,"用户名【{}】已被使用！", updateDTO.getUserName());

        // 2、检查手机号是否已存在
        Long updatePhoneCount = count(Wrappers.lambdaQuery(SystemUser.class)
                .eq(SystemUser::getPhone, updateDTO.getPhone())
                .ne(SystemUser::getId, updateDTO.getId()));
        Assert.isTrue(updatePhoneCount < 1,"手机号码【{}】已被使用！", updateDTO.getPhone());


        SystemUser systemUser = BeanUtil.toBean(updateDTO, SystemUser.class);
        //如果传了密码，则表示要重置密码
        if(StringUtils.hasText(updateDTO.getUserPassword()))
        {
            systemUser.setUserPassword(passwordEncoder.encode(updateDTO.getUserPassword()));
        }
        updateById(systemUser);

        //修改角色
        SystemUserAssignRoleDTO assignRoleDTO = new SystemUserAssignRoleDTO();
        assignRoleDTO.setId(systemUser.getId())
                .setRoleIdList(updateDTO.getRoleIdList());
        assignRole(assignRoleDTO);
        assignSystemDeptUser(systemUser.getId(), systemUser.getRealName(),systemUser.getDeptId());

    }

}
